package org.micode.libs.servlet.handler;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import org.apache.shiro.dao.DataAccessException;
import org.micode.common.domain.ApiResult;
import org.micode.common.enums.ResultEnum;
import org.micode.common.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.micode.common.helper.I18nMsgHelper;
import org.micode.common.utils.StringExtUtils;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
import java.util.List;

/**
 * 全局异常信息处理类
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ApiResult jsonErrorHandler(HttpServletRequest req, Exception e) {
        log.error("Handling exception found：", e);

        ApiResult result = new ApiResult();
        if (e instanceof BaseException) {
            BaseException be = (BaseException) e;
            result.setCode(be.getCode());
            result.setMsg(be.getMessage());
        } else if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException me = (MethodArgumentNotValidException) e;
            result.setCode(ResultEnum.VERIFY_ERROR.getCode());
            result.setMsg(getErrorMessage(me.getBindingResult()));
        } else if (e instanceof BindException) {
            BindException me = (BindException) e;
            result.setCode(ResultEnum.VERIFY_ERROR.getCode());
            result.setMsg(getErrorMessage(me.getBindingResult()));
        } else if (e instanceof MaxUploadSizeExceededException) {
            result.setCode(ResultEnum.VERIFY_ERROR.getCode());
            result.setMsg(
                    getLocaleMsg("MaxUploadSizeExceededException",
                            "The file size exceeds the maximum limit",
                            e.getMessage())
            );
        } else if (e instanceof InvalidFormatException) {
            result.setCode(ResultEnum.VERIFY_ERROR.getCode());
            result.setMsg(
                    getLocaleMsg("InvalidFormatException",
                            "Parameter type or format error",
                            e.getMessage())
            );
        } else if (e instanceof SQLException) {
            result.setCode(ResultEnum.INVOKE_FAIL.getCode());
            result.setMsg(
                    getLocaleMsg("SQLException",
                            "SQL processing exception",
                            e.getMessage())
            );
        } else if (e instanceof DataAccessException) {
            result.setCode(ResultEnum.INVOKE_FAIL.getCode());
            result.setMsg(
                    getLocaleMsg("DataAccessException",
                            "Database read/write exception",
                            e.getMessage())
            );
        } else if (e instanceof UncategorizedSQLException) {
            result.setCode(ResultEnum.INVOKE_FAIL.getCode());
            result.setMsg(
                    getLocaleMsg("UncategorizedSQLException",
                            "Uncategorized SQL exception",
                            e.getMessage())
            );
        } else {
            log.error("Unknown exception not handled properly({}}!!!", e.getMessage());
            result.setCode(ResultEnum.UNKNOWN.getCode());
            result.setMsg(
                    getLocaleMsg(e.getClass().getSimpleName(),
                            "Background processing exception, please contact the administrator",
                            e.getMessage())
            );
        }
        //添加异常信息
        req.setAttribute("exceptionClass", e.getClass().getName());
//            req.setAttribute("exceptionMessage", e.getLocalizedMessage());
        return result;
    }

    private String getLocaleMsg(String exceptionName, String defaultHint, String exceptMsg) {
        String ret = I18nMsgHelper.get("Exception." + exceptionName);
        if (StringExtUtils.isAnyEmpty(ret)) {
            return defaultHint + " : " + exceptMsg;
        } else {
            return ret + " : " + exceptMsg;
        }
    }

    /**
     * 获取错误信息
     *
     * @param bindingResult
     * @return
     */
    private String getErrorMessage(BindingResult bindingResult) {
        List<ObjectError> list = bindingResult.getAllErrors();
        StringBuilder message = new StringBuilder();
        for (ObjectError o : list) {
            if (o instanceof FieldError) {
                FieldError error = (FieldError) o;
                message.append(error.getField() + o.getDefaultMessage() + ";");
            } else {
                message.append(o.getDefaultMessage() + ";");
            }
        }
        return message.toString();
    }

}
